<!DOCTYPE html>
<!-- saved from url=(0118)http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2 -->
<html lang="en" dir="ltr" class="client-js"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Complete Roguelike Tutorial, using python+libtcod, part 2 - RogueBasin</title>
<meta charset="UTF-8">
<meta name="generator" content="MediaWiki 1.19.2">
<link rel="shortcut icon" href="http://roguebasin.roguelikedevelopment.org/favicon.ico">
<link rel="search" type="application/opensearchdescription+xml" href="http://roguebasin.roguelikedevelopment.org/opensearch_desc.php" title="RogueBasin (en)">
<link rel="EditURI" type="application/rsd+xml" href="http://roguebasin.roguelikedevelopment.org/api.php?action=rsd">
<link rel="alternate" type="application/atom+xml" title="RogueBasin Atom feed" href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:RecentChanges&feed=atom">
<link rel="stylesheet" href="http://roguebasin.roguelikedevelopment.org/load.php?debug=false&lang=en&modules=mediawiki.legacy.commonPrint%2Cshared%7Cskins.monobook&only=styles&skin=monobook&*">
<!--[if IE 6]><link rel="stylesheet" href="/skins/monobook/IE60Fixes.css?303" media="screen" /><![endif]-->
<!--[if IE 7]><link rel="stylesheet" href="/skins/monobook/IE70Fixes.css?303" media="screen" /><![endif]--><style type="text/css" media="all">.js-messagebox{margin:1em 5%;padding:0.5em 2.5%;border:1px solid #ccc;background-color:#fcfcfc;font-size:0.8em}.js-messagebox .js-messagebox-group{margin:1px;padding:0.5em 2.5%;border-bottom:1px solid #ddd}.js-messagebox .js-messagebox-group:last-child{border-bottom:thin none transparent}

/* cache key: 133099-basin:resourceloader:filter:minify-css:7:8b08bdc91c52a9ffba396dccfb5b473c */


.mw-collapsible-toggle{float:right} li .mw-collapsible-toggle{float:none} .mw-collapsible-toggle-li{list-style:none}

/* cache key: 133099-basin:resourceloader:filter:minify-css:7:4250852ed2349a0d4d0fc6509a3e7d4c */
</style><meta name="ResourceLoaderDynamicStyles" content="">
<link rel="stylesheet" href="http://roguebasin.roguelikedevelopment.org/load.php?debug=false&lang=en&modules=site&only=styles&skin=monobook&*">
<style>a:lang(ar),a:lang(ckb),a:lang(fa),a:lang(kk-arab),a:lang(mzn),a:lang(ps),a:lang(ur){text-decoration:none}a.new,#quickbar a.new{color:#ba0000}

/* cache key: 133099-basin:resourceloader:filter:minify-css:7:c88e2bcd56513749bec09a7e29cb3ffa */
</style>

<script src="./Complete Roguelike Tutorial, using python+libtcod, part 2 - RogueBasin_files/load.php"></script><style type="text/css"></style><script src="./Complete Roguelike Tutorial, using python+libtcod, part 2 - RogueBasin_files/load(1).php"></script>
<script>if(window.mw){
mw.config.set({"wgCanonicalNamespace":"","wgCanonicalSpecialPageName":false,"wgNamespaceNumber":0,"wgPageName":"Complete_Roguelike_Tutorial,_using_python+libtcod,_part_2","wgTitle":"Complete Roguelike Tutorial, using python+libtcod, part 2","wgCurRevisionId":35275,"wgArticleId":3588,"wgIsArticle":true,"wgAction":"view","wgUserName":null,"wgUserGroups":["*"],"wgCategories":["Developing"],"wgBreakFrames":false,"wgPageContentLanguage":"en","wgSeparatorTransformTable":["",""],"wgDigitTransformTable":["",""],"wgRelevantPageName":"Complete_Roguelike_Tutorial,_using_python+libtcod,_part_2","wgRestrictionEdit":[],"wgRestrictionMove":[]});
}</script><script>if(window.mw){
mw.loader.implement("user.options",function($){mw.user.options.set({"ccmeonemails":0,"cols":80,"date":"default","diffonly":0,"disablemail":0,"disablesuggest":0,"editfont":"default","editondblclick":0,"editsection":1,"editsectiononrightclick":0,"enotifminoredits":0,"enotifrevealaddr":0,"enotifusertalkpages":1,"enotifwatchlistpages":0,"extendwatchlist":0,"externaldiff":0,"externaleditor":0,"fancysig":0,"forceeditsummary":0,"gender":"unknown","hideminor":0,"hidepatrolled":0,"highlightbroken":1,"imagesize":2,"justify":0,"math":1,"minordefault":0,"newpageshidepatrolled":0,"nocache":0,"noconvertlink":0,"norollbackdiff":0,"numberheadings":0,"previewonfirst":0,"previewontop":1,"quickbar":5,"rcdays":7,"rclimit":50,"rememberpassword":0,"rows":25,"searchlimit":20,"showhiddencats":0,"showjumplinks":1,"shownumberswatching":1,"showtoc":1,"showtoolbar":1,"skin":"monobook","stubthreshold":0,"thumbsize":2,"underline":2,"uselivepreview":0,"usenewrc":0,"watchcreations":0,"watchdefault":0,"watchdeletion":
0,"watchlistdays":3,"watchlisthideanons":0,"watchlisthidebots":0,"watchlisthideliu":0,"watchlisthideminor":0,"watchlisthideown":0,"watchlisthidepatrolled":0,"watchmoves":0,"wllimit":250,"variant":"en","language":"en","searchNs0":true,"searchNs1":false,"searchNs2":false,"searchNs3":false,"searchNs4":false,"searchNs5":false,"searchNs6":false,"searchNs7":false,"searchNs8":false,"searchNs9":false,"searchNs10":false,"searchNs11":false,"searchNs12":false,"searchNs13":false,"searchNs14":false,"searchNs15":false});;},{},{});mw.loader.implement("user.tokens",function($){mw.user.tokens.set({"editToken":"+\\","watchToken":false});;},{},{});

/* cache key: 133099-basin:resourceloader:filter:minify-js:7:74a832f2292f1f4d40d425d223444e78 */
}</script>
<script>if(window.mw){
mw.loader.load(["mediawiki.page.startup","mediawiki.legacy.wikibits","mediawiki.legacy.ajax"]);
}</script><script type="text/javascript" src="./Complete Roguelike Tutorial, using python+libtcod, part 2 - RogueBasin_files/load(2).php"></script>
<style type="text/css">/*<![CDATA[*/
.source-python {line-height: normal;}
.source-python li, .source-python pre {
	line-height: normal; border: 0px none white;
}
/**
 * GeSHi Dynamically Generated Stylesheet
 * --------------------------------------
 * Dynamically generated stylesheet for python
 * CSS class: source-python, CSS id: 
 * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann
 * (http://qbnz.com/highlighter/ and http://geshi.org/)
 * --------------------------------------
 */
.python.source-python .de1, .python.source-python .de2 {font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;}
.python.source-python  {font-family:monospace;}
.python.source-python .imp {font-weight: bold; color: red;}
.python.source-python li, .python.source-python .li1 {font-weight: normal; vertical-align:top;}
.python.source-python .ln {width:1px;text-align:right;margin:0;padding:0 2px;vertical-align:top;}
.python.source-python .li2 {font-weight: bold; vertical-align:top;}
.python.source-python .kw1 {color: #ff7700;font-weight:bold;}
.python.source-python .kw2 {color: #008000;}
.python.source-python .kw3 {color: #dc143c;}
.python.source-python .kw4 {color: #0000cd;}
.python.source-python .co1 {color: #808080; font-style: italic;}
.python.source-python .coMULTI {color: #808080; font-style: italic;}
.python.source-python .es0 {color: #000099; font-weight: bold;}
.python.source-python .br0 {color: black;}
.python.source-python .sy0 {color: #66cc66;}
.python.source-python .st0 {color: #483d8b;}
.python.source-python .nu0 {color: #ff4500;}
.python.source-python .me1 {color: black;}
.python.source-python .ln-xtra, .python.source-python li.ln-xtra, .python.source-python div.ln-xtra {background-color: #ffc;}
.python.source-python span.xtra { display:block; }

/*]]>*/
</style>
<style type="text/css">/*<![CDATA[*/
@import "/index.php?title=MediaWiki:Geshi.css&usemsgcache=yes&action=raw&ctype=text/css&smaxage=18000";
/*]]>*/
</style></head>
<body class="mediawiki ltr sitedir-ltr ns-0 ns-subject page-Complete_Roguelike_Tutorial_using_python_libtcod_part_2 skin-monobook action-view">
<div id="globalWrapper">
<div id="column-content"><div id="content"><div id="mw-js-message" class="js-messagebox" style="display: none;"></div>
	<a id="top"></a>
	<div id="siteNotice"><div id="localNotice" lang="en" dir="ltr"></div></div>
	<h1 id="firstHeading" class="firstHeading"><span dir="auto">Complete Roguelike Tutorial, using python+libtcod, part 2</span></h1>
	<div id="bodyContent" class="mw-body">
		<div id="siteSub">From RogueBasin</div>
		<div id="contentSub"></div>
		<div id="jump-to-nav" class="mw-jump">Jump to: <a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2#column-one">navigation</a>, <a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2#searchInput">search</a></div>
		<!-- start content -->
<div id="mw-content-text" lang="en" dir="ltr" class="mw-content-ltr"><center><table border="0" cellpadding="10" cellspacing="0" style="background:#F0E68C"><tbody><tr><td><center>
<p>This is part of a series of tutorials; the main page can be found <a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod" title="Complete Roguelike Tutorial, using python+libtcod">here</a>.
</p><p>The tutorial uses libctod version 1.5.1. If you prefer to use 1.5.0, you can find the old version <a rel="nofollow" class="external text" href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2&oldid=29861">here</a>
</p>
</center></td></tr></tbody></table></center>
<table id="toc" class="toc"><tbody><tr><td><div id="toctitle"><h2>Contents</h2><span class="toctoggle">&nbsp;[<a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2#" class="internal" id="togglelink">hide</a>]&nbsp;</span></div>
<ul>
<li class="toclevel-1"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2#The_object_and_the_map"><span class="tocnumber">1</span> <span class="toctext"><b>The object and the map</b></span></a>
<ul>
<li class="toclevel-2 tocsection-1"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2#Off-screen_consoles"><span class="tocnumber">1.1</span> <span class="toctext">Off-screen consoles</span></a></li>
<li class="toclevel-2 tocsection-2"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2#Generalizing"><span class="tocnumber">1.2</span> <span class="toctext">Generalizing</span></a></li>
<li class="toclevel-2 tocsection-3"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2#The_Map"><span class="tocnumber">1.3</span> <span class="toctext">The Map</span></a></li>
</ul>
</li>
</ul>
</td></tr></tbody></table>
<p><br>
</p>
<center><h1> <span class="mw-headline" id="The_object_and_the_map"><b>The object and the map</b></span></h1></center>
<h2> <span class="mw-headline" id="Off-screen_consoles"> Off-screen consoles </span></h2>
<p>There's one small thing we need to get out of the way before we can continue. Notice that the drawing functions we called (<i>console_set_default_foreground</i> and <i>console_put_char</i>) have their first argument set to 0, meaning that they draw on the <i>root console</i>. This is the buffer that is shown directly on screen.
</p><p>It can be useful, however, to have other buffers to store the results of drawing functions without automatically showing them to the player. This is akin to drawing surfaces or buffers in other graphics libraries; but instead of pixels they store characters and colors so you can modify them at will. Some uses of these off-screen consoles include semi-transparency or fading effects and composing GUI panels by blitting them to different portions of the root console. We're going to draw on an off-screen console from now on. The main reason is that not doing so would mean that later on you can't compose different GUI panels as easily, or add certain effects.
</p><p>First, create a new off-screen console, which for now will occupy the whole screen, but this can be changed later. We'll use a simple name like <i>con</i> because it will be used <b>a lot</b>! You can put this in the initialization, right after <i>console_init_root</i>.
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">con = libtcod.<span class="me1">console_new</span><span class="br0">(</span>SCREEN_WIDTH, SCREEN_HEIGHT<span class="br0">)</span></pre></div></div></div>
<p><br>
Now change the first argument of <i>console_put_char</i> (there are 2 calls to this function) and <i>console_set_default_foreground</i>, from <i>0</i> to <i>con</i>. They're now drawing on the new console.
</p><p>Finally, just before <i>console_flush()</i>, blit the contents of the new console to the root console, to display them. The parameters may look a bit mysterious at first, but they're just saying that the source rectangle has its top-left corner at coordinates (0, 0) and is the same size as the screen; the destination coordinates are (0, 0) as well. Check the documentation on <a rel="nofollow" class="external text" href="http://doryen.eptalys.net/data/libtcod/doc/1.5.1/html2/console_offscreen.html?c=false&cpp=false&cs=false&py=true&lua=false#6">the console_blit function</a> for more details.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">libtcod.<span class="me1">console_blit</span><span class="br0">(</span>con, <span class="nu0">0</span>, <span class="nu0">0</span>, SCREEN_WIDTH, SCREEN_HEIGHT, <span class="nu0">0</span>, <span class="nu0">0</span>, <span class="nu0">0</span><span class="br0">)</span></pre></div></div></div>
<p><br>
That was a lot of talk for so little code and no visible change! The next section will surely be much more interesting, as we'll introduce our first dummy NPC among other things. Remember to check back the above documentation page when you get to coding your GUI.
</p><p><br>
</p>
<h2> <span class="mw-headline" id="Generalizing"> Generalizing </span></h2>
<p>Now that we have the @ walking around, it would be a good idea to step back and think a bit about the design. Having variables for the player's coordinates is easy, but it can quickly get out of control when you're defining things such as HP, bonuses, and inventory. We're going to take the opportunity to generalize a bit.
</p><p>Now, there <i>can</i> be such a thing as over-generalization, but we'll try not to fall in that trap. What we're going to do is define the player as a game <i>Object</i>, by creating that class. It will hold all position and display information (character and color). The neat thing is that the player will just be one instance of the <i>Object</i> class -- it's general enough that you can re-use it to define items on the floor, monsters, doors, stairs; anything representable by a character on the screen. Here's the class, with the initialization, and three common methods <i>move</i>, <i>draw</i> and <i>clear</i>. The code for drawing and erasing is the same as the one we used for the player earlier.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">class</span> Object:
    <span class="co1">#this is a generic object: the player, a monster, an item, the stairs...</span>
    <span class="co1">#it's always represented by a character on screen.</span>
    <span class="kw1">def</span> <span class="kw4">__init__</span><span class="br0">(</span><span class="kw2">self</span>, x, y, char, color<span class="br0">)</span>:
        <span class="kw2">self</span>.<span class="me1">x</span> = x
        <span class="kw2">self</span>.<span class="me1">y</span> = y
        <span class="kw2">self</span>.<span class="me1">char</span> = char
        <span class="kw2">self</span>.<span class="me1">color</span> = color
&nbsp;
    <span class="kw1">def</span> move<span class="br0">(</span><span class="kw2">self</span>, dx, dy<span class="br0">)</span>:
        <span class="co1">#move by the given amount</span>
        <span class="kw2">self</span>.<span class="me1">x</span> += dx
        <span class="kw2">self</span>.<span class="me1">y</span> += dy
&nbsp;
    <span class="kw1">def</span> draw<span class="br0">(</span><span class="kw2">self</span><span class="br0">)</span>:
        <span class="co1">#set the color and then draw the character that represents this object at its position</span>
        libtcod.<span class="me1">console_set_default_foreground</span><span class="br0">(</span>con, <span class="kw2">self</span>.<span class="me1">color</span><span class="br0">)</span>
        libtcod.<span class="me1">console_put_char</span><span class="br0">(</span>con, <span class="kw2">self</span>.<span class="me1">x</span>, <span class="kw2">self</span>.<span class="me1">y</span>, <span class="kw2">self</span>.<span class="me1">char</span>, libtcod.<span class="me1">BKGND_NONE</span><span class="br0">)</span>
&nbsp;
    <span class="kw1">def</span> clear<span class="br0">(</span><span class="kw2">self</span><span class="br0">)</span>:
        <span class="co1">#erase the character that represents this object</span>
        libtcod.<span class="me1">console_put_char</span><span class="br0">(</span>con, <span class="kw2">self</span>.<span class="me1">x</span>, <span class="kw2">self</span>.<span class="me1">y</span>, <span class="st0">' '</span>, libtcod.<span class="me1">BKGND_NONE</span><span class="br0">)</span></pre></div></div></div>
<p>Please not that there are <i>two</i> underscores on each side of <code>__init__</code>!
</p><p>Now, before the main loop, instead of just setting the player's coordinates, we create it as an actual <i>Object</i>. We also add it to a list, that will hold <i>all</i> objects that are in the game. While we're at it we'll add a yellow @ that represents a non-playing character, like in an RPG, just to test it out!
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">player = Object<span class="br0">(</span>SCREEN_WIDTH/<span class="nu0">2</span>, SCREEN_HEIGHT/<span class="nu0">2</span>, <span class="st0">'@'</span>, libtcod.<span class="me1">white</span><span class="br0">)</span>
npc = Object<span class="br0">(</span>SCREEN_WIDTH/<span class="nu0">2</span> - <span class="nu0">5</span>, SCREEN_HEIGHT/<span class="nu0">2</span>, <span class="st0">'@'</span>, libtcod.<span class="me1">yellow</span><span class="br0">)</span>
objects = <span class="br0">[</span>npc, player<span class="br0">]</span></pre></div></div></div>
<p><br>
We'll have to make a couple of changes now. First, in the <i>handle_keys</i> function, instead of dealing directly with the player's coordinates, we can use the player's <i>move</i> method with the appropriate displacement. Later this will come in handy as it can automatically check if the player (or another object) is about to hit a wall. Secondly, the main loop will now clear all objects like this:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">    <span class="kw1">for</span> <span class="kw2">object</span> <span class="kw1">in</span> objects:
        <span class="kw2">object</span>.<span class="me1">clear</span><span class="br0">(</span><span class="br0">)</span></pre></div></div></div>
<p><br>
And draw them like this:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">    <span class="kw1">for</span> <span class="kw2">object</span> <span class="kw1">in</span> objects:
        <span class="kw2">object</span>.<span class="me1">draw</span><span class="br0">(</span><span class="br0">)</span></pre></div></div></div>
<p><br>
Ok, that's all! A fully generic object system. Later, this class can be modified to have all the special info that items, monsters and all that will require. But we can add that as we go along!
</p><p><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2_code#Generalizing" title="Complete Roguelike Tutorial, using python+libtcod, part 2 code">Here</a>'s the code so far.
</p>
<h2> <span class="mw-headline" id="The_Map"> The Map </span></h2>
<p>Just like how you generalized the concept of the player object, you'll now do the same thing with the dungeon map. Your map will be a two-dimensional array of tiles where all your dungeon adventuring will happen. We'll start by defining its size at the top of the file. It's not quite the same size as the screen, to leave some space for a panel to show up later (where you can show stats and all). We'll try to make this as configurable as possible, this should suffice for now!
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">MAP_WIDTH = <span class="nu0">80</span>
MAP_HEIGHT = <span class="nu0">45</span></pre></div></div></div>
<p><br>
Next, the tile colors. For now there are two tile types -- wall and ground. These will be their "dark" colors, which you'll see when they're not in FOV; their "lit" counterparts are not needed right now. Notice that their values are between 0 and 255, if you found colors on the web in hexadecimal format you'll have to convert them with a calculator. Finding RGB values by educated trial-and-error works at first but with time you'll have a set of colors that don't mix together very well (contrast and tone as perceived by the human eye, and all that stuff), so it's usually better to look at a chart of colors; just search for "html colors" and use one you like.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">color_dark_wall = libtcod.<span class="me1">Color</span><span class="br0">(</span><span class="nu0">0</span>, <span class="nu0">0</span>, <span class="nu0">100</span><span class="br0">)</span>
color_dark_ground = libtcod.<span class="me1">Color</span><span class="br0">(</span><span class="nu0">50</span>, <span class="nu0">50</span>, <span class="nu0">150</span><span class="br0">)</span></pre></div></div></div>
<p><br>
What sort of info will each tile hold? We'll start simple, with two values that say whether a tile is passable or not, and whether it blocks sight. In this case, it's better to seperate them early, so later you can have see-through but unpassable tiles such as chasms, or passable tiles that block sight for secret passages. They'll be defined in a Tile class, that we'll add to as we go. Believe me, this class will quickly grow to have about a dozen different values for each tile!
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">class</span> Tile:
    <span class="co1">#a tile of the map and its properties</span>
    <span class="kw1">def</span> <span class="kw4">__init__</span><span class="br0">(</span><span class="kw2">self</span>, blocked, block_sight = <span class="kw2">None</span><span class="br0">)</span>:
        <span class="kw2">self</span>.<span class="me1">blocked</span> = blocked
&nbsp;
        <span class="co1">#by default, if a tile is blocked, it also blocks sight</span>
        <span class="kw1">if</span> block_sight <span class="kw1">is</span> <span class="kw2">None</span>: block_sight = blocked
        <span class="kw2">self</span>.<span class="me1">block_sight</span> = block_sight</pre></div></div></div>
<p><br>
As promised, the map is a two-dimensional array of tiles. The easiest way to do that is to have a list of rows, each row itself being a list of tiles, since there are no native multi-dimensional arrays in Python. We'll build it using a neat trick, <a rel="nofollow" class="external text" href="http://docs.python.org/tutorial/datastructures.html#list-comprehensions">list comprehensions</a>. See, the usual way to build lists (from C++ land) is to create an empty list, then iterate with a <i>for</i> and add elements gradually. But in Python, the syntax [<i>element</i> for <i>index</i> in <i>range</i>], where <i>index</i> and <i>range</i> are the same as what you'd use in a <i>for</i>, will return a list of <i>element</i>s. Just take a second to understand that sentence if you never worked with that before. With two of those, one for rows and another for tiles in each row, we create the map in one fell swoop! The linked page has a ton of examples on that, and also an example of <a rel="nofollow" class="external text" href="http://docs.python.org/tutorial/datastructures.html#nested-list-comprehensions">nested list comprehensions</a> like we're using for the map. Well, that's an awful lot of words for such a tiny piece of code!
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">def</span> make_map<span class="br0">(</span><span class="br0">)</span>:
    <span class="kw1">global</span> <span class="kw2">map</span>
&nbsp;
    <span class="co1">#fill map with "unblocked" tiles</span>
    <span class="kw2">map</span> = <span class="br0">[</span><span class="br0">[</span> Tile<span class="br0">(</span><span class="kw2">False</span><span class="br0">)</span>
        <span class="kw1">for</span> y <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span>MAP_HEIGHT<span class="br0">)</span> <span class="br0">]</span>
            <span class="kw1">for</span> x <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span>MAP_WIDTH<span class="br0">)</span> <span class="br0">]</span></pre></div></div></div>
<p><br>
Accessing the tiles is as easy as <i>map[x][y]</i>. Here we add two pillars (blocked tiles) to demonstrate that, and provide a simple test.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">    <span class="kw2">map</span><span class="br0">[</span><span class="nu0">30</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">22</span><span class="br0">]</span>.<span class="me1">blocked</span> = <span class="kw2">True</span>
    <span class="kw2">map</span><span class="br0">[</span><span class="nu0">30</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">22</span><span class="br0">]</span>.<span class="me1">block_sight</span> = <span class="kw2">True</span>
    <span class="kw2">map</span><span class="br0">[</span><span class="nu0">50</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">22</span><span class="br0">]</span>.<span class="me1">blocked</span> = <span class="kw2">True</span>
    <span class="kw2">map</span><span class="br0">[</span><span class="nu0">50</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">22</span><span class="br0">]</span>.<span class="me1">block_sight</span> = <span class="kw2">True</span></pre></div></div></div>
<p><br>
One very important piece of advice: <i>in list comprehensions, always call the constructor of the objects you're creating</i>, like we did with Tile(False). If we had tried to first create an unblocked tile like <i>floor = Tile(False)</i> and then in the list comprehension just refer to that same <i>floor</i>, we'd get all sorts of weird bugs! This is a common rookie (and veteran!) mistake in Python. That's because all elements in the list would point to the exact same Tile (the one you defined as <i>floor</i>), not copies of it. Changing a property of one element would appear to change it in other elements as well! Calling the constructor for every element ensures that each is a distinct instance.
</p><p><br>
Don't worry, we're already close to a playable version! Since we need to draw both the objects and the map, it now makes sense to put them all under a new function instead of directly in the main loop. Take the object rendering code to a new <i>render_all</i> function, and in its place (in the main loop) call <i>render_all()</i>.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">def</span> render_all<span class="br0">(</span><span class="br0">)</span>:
    <span class="co1">#draw all objects in the list</span>
    <span class="kw1">for</span> <span class="kw2">object</span> <span class="kw1">in</span> objects:
        <span class="kw2">object</span>.<span class="me1">draw</span><span class="br0">(</span><span class="br0">)</span></pre></div></div></div>
<p><br>
Still in the same function, we can now go through all the tiles and draw them to the screen, with the background color of a console character representing the corresponding tile. This will render the map.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">    <span class="kw1">for</span> y <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span>MAP_HEIGHT<span class="br0">)</span>:
        <span class="kw1">for</span> x <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span>MAP_WIDTH<span class="br0">)</span>:
            wall = <span class="kw2">map</span><span class="br0">[</span>x<span class="br0">]</span><span class="br0">[</span>y<span class="br0">]</span>.<span class="me1">block_sight</span>
            <span class="kw1">if</span> wall:
                libtcod.<span class="me1">console_set_char_background</span><span class="br0">(</span>con, x, y, color_dark_wall, libtcod.<span class="me1">BKGND_SET</span> <span class="br0">)</span>
            <span class="kw1">else</span>:
                libtcod.<span class="me1">console_set_char_background</span><span class="br0">(</span>con, x, y, color_dark_ground, libtcod.<span class="me1">BKGND_SET</span> <span class="br0">)</span></pre></div></div></div>
<p><br>
Also, move the <i>console_blit</i> call to the end of <i>render_all()</i> since it's part of the rendering code, just to keep things tidy.
</p><p>A little note on customization: if you want a more old-school look, using characters like ' <b>.</b> ' and ' <b>#</b> ' to represent floor and wall tiles, <a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_Python%2Blibtcod,_extras#Old-school_wall_and_floor_tiles" title="Complete Roguelike Tutorial, using Python+libtcod, extras">check out this Extra</a>.
</p><p><br>
Ok! Don't forget to call <i>make_map()</i> before the main loop, to set it up before the game begins. You should be able to see the two pillars and walk around the map now!
</p><p>But wait, there's something wrong. The pillars show up, but the player can walk over them. That's easy to fix though, add this check to the beginning of the <i>Object</i> 's <i>move</i> method:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">if</span> <span class="kw1">not</span> <span class="kw2">map</span><span class="br0">[</span><span class="kw2">self</span>.<span class="me1">x</span> + dx<span class="br0">]</span><span class="br0">[</span><span class="kw2">self</span>.<span class="me1">y</span> + dy<span class="br0">]</span>.<span class="me1">blocked</span>:</pre></div></div></div>
<p><br>
<a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2_code#The_Map" title="Complete Roguelike Tutorial, using python+libtcod, part 2 code">Here</a>'s the code so far.
</p><p><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_3" title="Complete Roguelike Tutorial, using python+libtcod, part 3">Go on to the next part</a>.
</p>
<!-- 
NewPP limit report
Preprocessor node count: 155/1000000
Post-expand include size: 0/2097152 bytes
Template argument size: 0/2097152 bytes
Expensive parser function count: 0/100
-->

<!-- Saved in parser cache with key 133099-basin:pcache:idhash:3588-0!*!0!!en!*!* and timestamp 20131206225235 -->
</div><div class="printfooter">
Retrieved from "<a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2&oldid=35275">http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2&amp;oldid=35275</a>"</div>
		<div id="catlinks" class="catlinks"><div id="mw-normal-catlinks" class="mw-normal-catlinks"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:Categories" title="Special:Categories">Category</a>: <ul><li><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Category:Developing" title="Category:Developing">Developing</a></li></ul></div></div>		<!-- end content -->
				<div class="visualClear"></div>
	</div>
</div></div>
<div id="column-one">
	<div id="p-cactions" class="portlet">
		<h5>Views</h5>
		<div class="pBody">
			<ul>
				<li id="ca-nstab-main" class="selected"><a href="./Complete Roguelike Tutorial, using python+libtcod, part 2 - RogueBasin_files/Complete Roguelike Tutorial, using python+libtcod, part 2 - RogueBasin.html" primary="1" context="subject" title="View the content page [alt-c]" accesskey="c">Page</a></li>
				<li id="ca-talk"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Talk:Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2" primary="1" context="talk" title="Discussion about the content page [alt-t]" accesskey="t">Discussion</a></li>
				<li id="ca-viewsource"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2&action=edit" primary="1" title="This page is protected.
You can view its source [alt-e]" accesskey="e">View source</a></li>
				<li id="ca-history"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2&action=history" rel="archives" title="Past revisions of this page [alt-h]" accesskey="h">History</a></li>
			</ul>
		</div>
	</div>
	<div class="portlet" id="p-personal">
		<h5>Personal tools</h5>
		<div class="pBody">
			<ul>
				<li id="pt-login"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:UserLogin&returnto=Complete+Roguelike+Tutorial%2C+using+python%2Blibtcod%2C+part+2" title="You are encouraged to log in; however, it is not mandatory [alt-o]" accesskey="o">Log in / create account</a></li>
			</ul>
		</div>
	</div>
	<div class="portlet" id="p-logo">
<a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Main_Page" style="background-image: url(/skins/roguebasin/RogueBasin_logo.png);" title="Visit the main page"></a>
	</div>
	<div class="generated-sidebar portlet" id="p-navigation">
		<h5>Navigation</h5>
		<div class="pBody">
			<ul>
				<li id="n-mainpage"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Main_Page" title="Visit the main page [alt-z]" accesskey="z">Main Page</a></li>
				<li id="n-portal"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=RogueBasin:Community_portal" title="About the project, what you can do, where to find things">Community portal</a></li>
				<li id="n-recentchanges"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:RecentChanges" title="A list of recent changes in the wiki [alt-r]" accesskey="r">Recent changes</a></li>
				<li id="n-randompage"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:Random" title="Load a random page [alt-x]" accesskey="x">Random page</a></li>
				<li id="n-help"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Help" title="The place to find out">Help</a></li>
			</ul>
		</div>
	</div>
	<div id="p-search" class="portlet">
		<h5><label for="searchInput">Search</label></h5>
		<div id="searchBody" class="pBody">
			<form action="http://roguebasin.roguelikedevelopment.org/index.php" id="searchform">
				<input type="hidden" name="title" value="Special:Search">
				<input type="search" name="search" title="Search RogueBasin [alt-f]" accesskey="f" id="searchInput">
				<input type="submit" name="go" value="Go" title="Go to a page with this exact name if exists" id="searchGoButton" class="searchButton">&nbsp;
				<input type="submit" name="fulltext" value="Search" title="Search the pages for this text" id="mw-searchButton" class="searchButton">
			</form>
		</div>
	</div>
	<div class="portlet" id="p-tb">
		<h5>Toolbox</h5>
		<div class="pBody">
			<ul>
				<li id="t-whatlinkshere"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:WhatLinksHere/Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2" title="A list of all wiki pages that link here [alt-j]" accesskey="j">What links here</a></li>
				<li id="t-recentchangeslinked"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:RecentChangesLinked/Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2" title="Recent changes in pages linked from this page [alt-k]" accesskey="k">Related changes</a></li>
				<li id="t-specialpages"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:SpecialPages" title="A list of all special pages [alt-q]" accesskey="q">Special pages</a></li>
				<li><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2&printable=yes" rel="alternate">Printable version</a></li>
				<li id="t-permalink"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_2&oldid=35275" title="Permanent link to this revision of the page">Permanent link</a></li>
			</ul>
		</div>
	</div>
</div><!-- end of the left (by default at least) column -->
<div class="visualClear"></div>
<div id="footer">
	<div id="f-poweredbyico">
		<a href="http://www.mediawiki.org/"><img src="./Complete Roguelike Tutorial, using python+libtcod, part 2 - RogueBasin_files/poweredby_mediawiki_88x31.png" alt="Powered by MediaWiki" width="88" height="31"></a>
	</div>
	<ul id="f-list">
		<li id="lastmod"> This page was last modified on 22 May 2013, at 23:25.</li>
		<li id="viewcount">This page has been accessed 32,987 times.</li>
		<li id="privacy"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=RogueBasin:Privacy_policy" title="RogueBasin:Privacy policy">Privacy policy</a></li>
		<li id="about"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=RogueBasin:About" title="RogueBasin:About">About RogueBasin</a></li>
		<li id="disclaimer"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=RogueBasin:General_disclaimer" title="RogueBasin:General disclaimer">Disclaimers</a></li>
	</ul>
</div>
</div>
<script>if(window.mw){
mw.loader.load(["mediawiki.user","mediawiki.page.ready"], null, true);
}</script><script src="./Complete Roguelike Tutorial, using python+libtcod, part 2 - RogueBasin_files/load(3).php" type="text/javascript"></script>
<script src="./Complete Roguelike Tutorial, using python+libtcod, part 2 - RogueBasin_files/load(4).php"></script>
<!-- Served in 0.443 secs. --><autoscroll_cursor hidden=""></autoscroll_cursor></body></html>